/**
 * Software License, Version 1.0
 * 
 * Copyright 2003 The Trustees of Indiana University.  All rights reserved.
 * 
 *
 *Redistribution and use in source and binary forms, with or without 
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the 
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For 
 * further information contact the Community Grids Lab at 
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and 
 * wherever such third-party acknowledgments normally appear.
 * 
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering, 
 * shall not be used to endorse or promote products derived from this software 
 * without prior written permission from Indiana University.  For written 
 * permission, please contact the Advanced Research and Technology Institute 
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering, 
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 * 
 *
 * Indiana University provides no reassurances that the source code provided 
 * does not infringe the patent or any other intellectual property rights of 
 * any other entity.  Indiana University disclaims any liability to any 
 * recipient for claims brought by any other entity based on infringement of 
 * intellectual property rights or otherwise.  
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO 
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF 
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS. 
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS", 
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.  
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR 
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION 
 *GENERATED USING SOFTWARE.
 */
package cgl.narada.samples.rtp;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;
import java.util.StringTokenizer;

import cgl.narada.protocol.GatewayInfo;
import cgl.narada.protocol.NodeAddress;
import cgl.narada.protocol.ProtocolHandler;
import cgl.narada.transport.TransportException;


/**
 * RTPServer.java
 * @author Shrideep Pallickara, Ahmet Uyar
 * $Revision$
 * $Date$
 */
public class RTPServer {
   /** The nodeAddress for this specific Server Node */
   private NodeAddress thisNodeAddress;

   /** Specifies the number of links allowed at each level. A 0 at level-i
       indicates that this node can never be a level-i gateway */
   private short[] connectionVector = { 5, 4, 3, 0, 0 };

   /** Use by the NodeAdditonProtocol to decide if a node should be allowed to
       be part of its unit/super-unit.*/
   private String ipDiscriminator;

   /** The number of levels used by the system */
   private short systemLevels;

   /** The protocol Handler */
   private ProtocolHandler protocolHandler;

   /** Gateway Info : Maintains information about revelant gatekeepers within
       the system */
   private GatewayInfo gatewayInfo;

   public RTPServer(boolean assignedAddress) {
      systemLevels = 3;

      int[] address = new int[systemLevels + 1];
      ipDiscriminator = "128.230";

      int addressId;

      /** An address of 0.0.0.0 indicates that this node needs an address */
      if (assignedAddress) {
         addressId = 1;
      } else {
         addressId = 0;
      }

      for (int i = 0; i < (systemLevels + 1); i++)
         address[i] = addressId;

      gatewayInfo = new GatewayInfo(systemLevels);

      thisNodeAddress = new NodeAddress(address);

      protocolHandler = new ProtocolHandler(thisNodeAddress, connectionVector, 5000/*concurrentConnLimit*/
      , ipDiscriminator, gatewayInfo);
      protocolHandler.initializeProtocolSuite();

      if (assignedAddress) {
         protocolHandler.setAssignedAddress(thisNodeAddress);
      }

      //protocolHandler.start();
      gatewayInfo.setProtocolHandler(protocolHandler);

   }

   public void setUpNode(Properties props, String transportType) {
      try {
         protocolHandler.loadCommunicationsOfType(props, transportType);
      } catch (TransportException transEx) {
         System.out.println(transEx);
      }
   }

   public void nodeAdditionRequest(String node, int level) {
      int[] levels = { 0, level };
      byte[] request = protocolHandler.constructNodeAdditionRequest(levels, true);
      if (request == null) {
          return;
      }
      protocolHandler.sendTo(node, request);
   }

   public void gatewayCreationRequest(String node, int gatewayLevel) {
      byte[] request = protocolHandler.constructGatewaySetupRequest(node, gatewayLevel);

      if (request == null) {
         return;
      }

      protocolHandler.sendTo(node, request);
   }

   public void connectTo(String hostName, int portNum, byte transport) {
      Properties props = new Properties();
      props.put("hostname", hostName);
      props.put("portnum", Integer.toString(portNum));

      try {
         protocolHandler.setupLink(props, "tcp");
      } catch (TransportException transEx) {
         System.out.println(transEx);
      }
   }

   public void createLink(Properties props, String transportType) {
      try {
         protocolHandler.setupLink(props, transportType);
      } catch (TransportException transEx) {
         System.out.println(transEx);
      }
   }

   public void sendTo(String client, byte[] data) {
      protocolHandler.sendTo(client, data);
   }

  /**
   * read the configuration file and set up the metting specified over there
   */
  public void setupMeetings(String confFile){
    try{
      
      int audioMeetingID = -1;
      int videoMeetingID = -1; //videoMeetinID = audioMeetingID + 1
      
      BufferedReader reader = new BufferedReader(new FileReader(confFile));
      String oneLine = reader.readLine();
      
      while(oneLine != null){
	
	//if the line begins with "#" or the length of it is zero, ignore 
	//that line and proceed to the next one
	if(oneLine.startsWith("#") || oneLine.trim().length() == 0){
	  
	  //if the line begins with "meeting-id", create a new meeting
	}else if(oneLine.startsWith("meeting-id")){
	  StringTokenizer tokenizer = new StringTokenizer(oneLine, "= ");
	  tokenizer.nextToken();
	  audioMeetingID = Integer.parseInt(tokenizer.nextToken());
	  videoMeetingID = audioMeetingID + 1;
	  //System.out.println("audioMeetingID: "+audioMeetingID);
	  //System.out.println("videoMeetingID: "+videoMeetingID);
	  addMeeting(audioMeetingID);
	  addMeeting(videoMeetingID);
	  
	  //else the line should have 
	  //a participant info, <ip> <audioport> <videoport>
	}else {
	  StringTokenizer tokenizer = new StringTokenizer(oneLine);
	  String ip = tokenizer.nextToken();
	  int audioPort = Integer.parseInt(tokenizer.nextToken());
	  int videoPort = Integer.parseInt(tokenizer.nextToken());
	  // System.out.println("ip: "+ip);
	  // System.out.println("audioPort: "+audioPort);
	  // System.out.println("videoPort: "+videoPort);
	  addParticipant(audioMeetingID, ip, audioPort);
	  addParticipant(videoMeetingID, ip, videoPort);
	}

	//read the next line
	oneLine = reader.readLine();
	
      }//end of while
      
    }catch(IOException ioe){
      System.err.println("configuration file is bad.");
      ioe.printStackTrace();
    }
  }
  
  /**
   * add a meeting, currently doing nothing
   */
  public void addMeeting(int meetingID){
    
    if(meetingID == -1){
      System.err.println("meeting-id can not be -1");
      return;
    }
  }
  
  /**
   * add a participant to a meeting
   */
  public void addParticipant(int meetingID, String ip, int port){
    
    Properties link = new Properties();
    link.put("dataPortLocal", Integer.toString(port));
    link.put("rtpHost", ip);
    link.put("rtpDataPort", Integer.toString(port));
    link.put("rtpMeetingId", Integer.toString(meetingID));
    createLink(link, "rtp");
  }
  
  public static void main(String[] args) {
    
    if (args.length != 1) {
      System.out.println("Usage: java cgl.narada.samples.rtp.RTPServer" + 
			 "  portNum  confFile ");
      System.exit(0);
    }
    
    String confFile = args[0];
    
    RTPServer rtpServer = new RTPServer(true);
    
    String portNum = "3045";
    Properties props = new Properties();
    props.put("UDPListenerPort", portNum);
    props.put("MulticastGroupHost", "224.224.224.224");
    props.put("MulticastGroupPort", "3045");
    
    rtpServer.setUpNode(props, "rtp");
    rtpServer.setupMeetings(confFile);
    
    try{
      while(true)
	Thread.sleep(10000000);
    }catch(Exception e){
      e.printStackTrace();
    }
    
  }
}


